package demoMod.stsconsole.relics;

import demoMod.stsconsole.ConsoleEntry;
import demoMod.stsconsole.annotations.DataSaver;
import demoMod.stsconsole.dungeons.AbstractDungeon;
import demoMod.stsconsole.enums.SubscriberPriority;
import demoMod.stsconsole.helpers.LocalizedStrings;
import demoMod.stsconsole.helpers.RandomSequence;
import demoMod.stsconsole.interfaces.*;
import demoMod.stsconsole.saves.RelicSaver;

import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@DataSaver(cls = RelicSaver.class)
public abstract class AbstractRelic implements ReloadStringsSubscriber, CustomSavable<Map<String, Object>>, Saleable, ChangePriceSubscriber {
    protected List<String> relicStrings;

    public String id;
    public String name;
    public String flavor;
    public String description;
    public RelicRarity rarity;
    public RelicColor color;
    public int counter;

    public boolean isPriceInitialized = false;
    public int price;

    public AbstractRelic(String id) {
        this.id = id;
        onReloadStrings();
        ConsoleEntry.subscribers.add(this);
    }

    public abstract String getUpdatedDescriptions();

    @Override
    public void onReloadStrings() {
        this.relicStrings = LocalizedStrings.getRelicStrings(id);
        this.name = relicStrings.get(0);
        this.flavor = relicStrings.get(1);
        this.description = relicStrings.get(2);
    }

    @Override
    public boolean enabled(Class<? extends ISubscriber> cls) {
        return cls.getSimpleName().equals("ReloadStringsSubscriber") || (AbstractDungeon.player != null && AbstractDungeon.player.getRelics().contains(this));
    }

    public AbstractRelic makeCopy() {
        try {
            return this.getClass().newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }

    public boolean canSpawn() {
        return true;
    }

    public void onRemove() {
        ConsoleEntry.removeLater.add(this);
    }

    @Override
    public int getPriority() {
        return SubscriberPriority.RELIC.getPriority();
    }

    @Override
    public Map<String, Object> onSave() {
        Map<String, Object> ret = new HashMap<>();
        ret.put("counter", this.counter);
        return ret;
    }

    @Override
    public void onLoad(Map<String, Object> save) {
        if (save != null) {
            this.counter = (int) save.getOrDefault("counter", 0);
        }
    }

    @Override
    public int onChangePrice(Saleable product, int price, RandomSequence rng) {
        if (product == this) {
            if (!isPriceInitialized) {
                price *= (rng.nextFloat() - 0.5F) * 0.2F + 1.0F;
                this.isPriceInitialized = true;
            }
            this.price = price;
        }
        return price;
    }

    @Override
    public void calculatePrice(RandomSequence rng) {
        this.price = getBasePrice();
        ConsoleEntry.triggerSubscribers(
                ChangePriceSubscriber.class,
                "onChangePrice",
                new Class[]{Saleable.class, int.class, RandomSequence.class},
                new Object[]{this, this.price, rng},
                (method, params, subscriber) -> {
                    if (params[0] == this) {
                        try {
                            params[1] = method.invoke(subscriber, params);
                        } catch (IllegalAccessException | InvocationTargetException e) {
                            e.printStackTrace();
                        }
                    }
                }
        );
    }

    @Override
    public int getBasePrice() {
        int price = 9999;
        switch (this.rarity) {
            case STARTER:
            case COMMON:
            case SHOP:
                price = 150;
                break;
            case UNCOMMON:
                price = 250;
                break;
            case RARE:
                price = 300;
                break;
            case BOSS:
                price = 999;
                break;
            case SPECIAL:
                price = 400;
        }
        return price;
    }

    @Override
    public int getPrice() {
        return this.price;
    }

    @Override
    public void purchase() {
        AbstractDungeon.player.obtainRelic(this.id);
    }

    public enum RelicRarity {
        STARTER, COMMON, UNCOMMON, RARE, BOSS, SHOP, SPECIAL
    }

    public enum RelicColor {
        SHARED, RED, GREEN, BLUE, PURPLE
    }
}
